package com.xinz.server;

import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xinz.Constants;
import com.xinz.cache.PlayerCache;
import com.xinz.model.Player;
import com.xinz.service.SpotService;

/**
 * 选手匹配
 *
 */
public class MatchServer {

	private static final Logger log = LoggerFactory.getLogger(MatchServer.class);
	
	public static MatchServer instance = new MatchServer();
	
	// 积分关系Map<场次, Map<积分区间, 参赛者列表>>
	private Map<Integer, Map<String, LinkedList<String>>> roomMap = new ConcurrentHashMap<Integer, Map<String, LinkedList<String>>>();
	
	/**
	 * 初始化场次关系
	 * 积分分4个档次
	 * 1、普通档
	 * 2、100档
	 * 3、200档
	 * 4、500档
	 */
	public void init() {
		// 普通档
		initNumber(1, 5);
		// 100档
		initNumber(2, 10);
		// 200档
		initNumber(3, 20);
		// 500档
		initNumber(4, 30);
	}
	
	/**
	 * 初始化场次，结果为<场次，Map<区间,列表>
	 * @param number 场次
	 * @param mod 系数，值越大人越集中
	 */
	private void initNumber(int number, int mod) {
		Map<String, LinkedList<String>> scoreMap = new ConcurrentHashMap<String, LinkedList<String>>();
		for(int i = 0; i <= 7000; ++i){
			if(i != 0 && i % mod == 0){
				scoreMap.put( i - mod + "_" + i, new LinkedList<String>());
			}
		}
		roomMap.put(number, scoreMap);
	}
	
	/**
	 * 根据积分和系数获取key
	 * @param score
	 * @param coefficient
	 * @return
	 */
	private String getKey(int score, int mod){
		if(score < 0) {
			score = 0;
		}
		int temp = score / mod;
		return temp * mod + "_" + (temp + 1) * mod;
	}
	
	/**
	 * 根据场次获取模
	 * @param number
	 * @return
	 */
	private int getMod( int number ){
		int mod = 5; 
		if( number==2 ){
			mod = 10; 
		}
		if( number==3 ){
			mod = 20; 
		}
		if( number==4 ){
			mod = 20;
		}
		return mod;
	}
	
	/**
	 * 获取房间数据
	 * @return
	 */
	public Map<Integer,Map<String,LinkedList<String>>> getRoomMap(){
		return roomMap;
	}
	
	/**
	 * 选手/参赛者进场 (选区或者换桌时执行)
	 * 
	 * @param number
	 * @param uid 
	 * @param score 积分
	 */
	public synchronized void entryRoom(Player player, int room) {
		// 已经在棋局中进入
		if(player.getTargetPid() != null && player.getBattleStatus() == Constants.BATTLE_STATUS_GAMING) {
			log.error("player is gaming:" + player.getId() + ",target:" + player.getTargetPid());
			return;
		}
		String pid = player.getId();
		log.info("entryRoom:" + room + "," + pid + "," + player.getScore());
		int score = player.getScore();
		// 分组、场次
		Map<String,LinkedList<String>> scoreMap = roomMap.get(room);
		int mod = getMod(room);
		String key = getKey(score, mod);
		player.setRoom(room);
		
		// 检查玩家是否在cache中，不存在则添加到Cache
		if(player.getBattleStatus()==Constants.BATTLE_STATUS_UNENTRY){
			// 添加玩家到等待队列
			LinkedList<String> contestantList = scoreMap.get(key);
			contestantList.add(pid);
			
			// 添加到游戏中列表
			player.setBattleStatus(Constants.BATTLE_STATUS_MATCH);
		}
		
		if(player.getCamp() == -1){
			// 玩家默认在红方
			player.setCamp(0);
		}
		
		// 匹配玩家：规则（从该玩家积分开始向下和向上查找玩家找到就配对，找不到就取消），如果都没有匹配到玩家，从最大的值网上寻找
		boolean isMatch = false;	// 是否匹配到玩家
		String tempKey = "0_5";		// 初始区间段
		for(int i = 0; i <= score / mod; ++i){
			if(i == 0){
				// 本区间段寻找
				tempKey = getKey(score, mod);
				isMatch = match(player, scoreMap, tempKey);	
				if(isMatch) break;
			}
			else{
				// 向下寻找
				tempKey = getKey(score - mod * i, mod);
				isMatch = match(player, scoreMap, tempKey);
				if(isMatch) break;
				// 向上寻找
				tempKey = getKey(score + mod * i, mod);
				isMatch = match(player, scoreMap, tempKey);
				if(isMatch) break;
			}
		}
		// 没有从相近的区间匹配到玩家
		if(!isMatch){
			// 最大区间的值 从这个值网上匹配玩家
			int maxInterval = Integer.parseInt(tempKey.split("[_]")[0]); 
			for(int i=maxInterval+mod;i<7000;i=i+mod){
				tempKey = getKey( i, mod );
				isMatch = match(player, scoreMap, tempKey);
				if(isMatch) break;
			}
		}
	}
	
	/**
	 * 匹配和自己水平相近的玩家
	 * @param player
	 * @param scoreMap
	 * @param tempKey
	 * @return
	 */
	private boolean match(Player player, Map<String,LinkedList<String>> scoreMap, String tempKey){
		String pid = player.getId();
		LinkedList<String> contestantList = scoreMap.get(tempKey);
		for(String tmpPid : contestantList){
			// 如果是自己则继续
			if(pid.equals(tmpPid)) continue;
			// 等待状态速配成功，设置双方游戏对象
			Player target = PlayerCache.instance.getPlayer(tmpPid);
			// 对方身上没有绑定其它玩家时就匹配成功
			if(target != null && target.getTargetPid() == null && player.getTargetPid() == null) {
				
				if(target.getBattleStatus()==Constants.BATTLE_STATUS_GAMING) continue;
				player.setBattleStatus(Constants.BATTLE_STATUS_CONFIRM);
				if(target.getBattleStatus()<Constants.BATTLE_STATUS_START){
					target.setBattleStatus(Constants.BATTLE_STATUS_CONFIRM);
				}
				// 设置速配双方玩家数据
				player.setTargetPid(tmpPid);
				long matchTime = System.currentTimeMillis();
				player.setMatchTime(matchTime);
				// 对方身上的状态
				target.setTargetPid(pid);
				target.setMatchTime(matchTime);
				// 和对方相反阵营
				if( target.getCamp()==0 ){
					// 自己在绿方
					player.setCamp(1);
				}
				else{
					player.setCamp(0);
				}
				// 匹配成功纪录日志
				log.info("match:" + player.getCamp() + "," + player.getId() + "|target:" + target.getCamp() + "," + target.getId());
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 棋局开始之前退出棋局<br/>
	 * 规则：<br/>
	 * 1、如果在棋局中则直接对方胜利 
	 * 2、确认状态退出是否需要惩罚
	 * 3、成功退出棋局需要更新状态为
	 */
	public void quit(Player self){
		// 退出设置状态为未进入 
		self.setBattleStatus(Constants.BATTLE_STATUS_UNENTRY);
		
		Player target = PlayerCache.instance.getPlayer(self.getTargetPid());
		if( target != null ){
			target.setBattleStatus(Constants.BATTLE_STATUS_UNENTRY);
			target.setTargetPid(null);
			target.setMatchTime(0);
		}
		
		self.setTargetPid(null);
		self.setMatchTime(0);	
		// 棋局是否已开始，开始后直接判对方胜利
	}
	
	/**
	 * 每次战斗结束从匹配列表中清理掉
	 *  
	 */
	public void clearScoreMap(Player player){
		int room = player.getRoom();
		if(room == 0) {
			log.error("room error,player:" + player.getId());
			return;
		}
		int score = player.getScore();
		String pid = player.getId();
		Map<String,LinkedList<String>> scoreMap = roomMap.get(room);
		if(scoreMap==null) {
			log.error("room error,integralMap is null:" + player.getId());
			return;
		}
		int mod = getMod( room );
		String key = getKey(score, mod);
		LinkedList<String> idList = scoreMap.get(key);
		if(idList != null && pid != null){
			idList.remove(pid);
		}
	}
	
	/**
	 * 初始化玩家棋局状态
	 */
	public void initPlayerChessStatus(Player player){
		// 解除自己和对方的关系
		player.setBattleStatus(Constants.BATTLE_STATUS_UNENTRY);

		if(player.getTargetPid()!=null){
			Player target = PlayerCache.instance.getPlayer(player.getTargetPid());
				target.setBattleStatus(Constants.BATTLE_STATUS_UNENTRY);
				target.setTargetPid(null);
				target.setMatchTime(0);
		}
		player.setTargetPid(null);
		player.setMatchTime(0);
	}
	
	/**
	 * 确认
	 * 双方状态为开始的话则进入游戏
	 */
	public void ready(Player player) {
		// 没有匹配到玩家
		if(player.getTargetPid() == null){
			// 标记自己为开始状态
			player.setBattleStatus(Constants.BATTLE_STATUS_START);
			return;
		}
		// 检查对方状态，如果对方状态为开始，则直接开始游戏
		Player target = PlayerCache.instance.getPlayer(player.getTargetPid());
		if(target == null){
			// 对方已离开
			player.setTargetPid(null);
		}
		else{
			// 对方也为开始状态，则开始游戏
			if(target.getBattleStatus()==Constants.BATTLE_STATUS_START){
				// 双方状态为开始游戏
				player.setBattleStatus(Constants.BATTLE_STATUS_GAMING);
				target.setBattleStatus(Constants.BATTLE_STATUS_GAMING);
				// 开始棋局
				SpotService.startSpot(player, target);
			}
			else{
				// 标记自己为开始状态
				player.setBattleStatus(Constants.BATTLE_STATUS_START);
			}
		}
	}
}
